/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus' Graphical User Interface
// Copyright (C) 2012-2025 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef TGUI_BACKEND_HPP
#define TGUI_BACKEND_HPP

#include <TGUI/Font.hpp>
#include <TGUI/Event.hpp>
#include <TGUI/Cursor.hpp>
#include <TGUI/Backend/Font/BackendFont.hpp>
#include <TGUI/Backend/Font/BackendFontFactory.hpp>
#include <TGUI/Backend/Renderer/BackendText.hpp>
#include <TGUI/Backend/Renderer/BackendTexture.hpp>
#include <TGUI/Backend/Renderer/BackendRenderer.hpp>

#include <cstdint>
#include <memory>
#include <set>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace tgui
{
    class Sprite;
    class Backend;
    class BackendGui;
    class BackendRenderer;
    class BackendFontFactory;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief Checks whether the backend differs from a nullptr
    /// @return Has setBackend been called with a valid backend?
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    TGUI_API bool isBackendSet();

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief Changes the global backend
    ///
    /// This function is automatically called when the first Gui object is created. When all Gui objects have been destructed,
    /// this function will be called again with a nullptr as parameter to destroy all global resources.
    ///
    /// If you want to use TGUI functionality before creating a Gui object then you should call this function directly.
    ///
    /// @warning When calling the function directly, it has to be the first call to TGUI and you must call setBackend(nullptr)
    ///          before the end of the main() function.
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    TGUI_API void setBackend(std::shared_ptr<Backend> backend);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief Returns the global backend
    ///
    /// @return Global backend
    ///
    /// @warning This function will assert if no backend has been created yet or after it has been destroyed.
    /// @see isBackendSet()
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    TGUI_API std::shared_ptr<Backend> getBackend();


    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief Base class for the backend
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    class TGUI_API Backend
    {
    public:

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Default constructor
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Backend() = default;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // The object cannot be copied
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Backend(const Backend&) = delete;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // The object cannot be copied
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Backend& operator=(const Backend&) = delete;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Virtual destructor
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual ~Backend() = default;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Informs the backend whether it should destroy itself when the last Gui is detached from it.
        ///
        /// @param destroyOnDetatch  Should setBackend(nullptr) be called when there are no more Gui objects left?
        ///
        /// This function will be called with "true" as parameter if the Backend is created by a Gui object.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void setDestroyOnLastGuiDetatch(bool destroyOnDetatch);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Informs the backend that a new gui object has been created.
        /// @param gui  Newly created gui
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void attachGui(BackendGui* gui);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Informs the backend that a gui object is being destroyed.
        /// @param gui  Gui object that is about to be deconstructed
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void detatchGui(BackendGui* gui);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Creates and returns the default font for all widgets
        /// @return Default font
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD virtual Font createDefaultFont();

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Creates a new font object
        /// @return Font that is specific to the backend
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD std::shared_ptr<BackendFont> createFont();

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Creates a new text object
        /// @return Text that is specific to the backend
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD std::shared_ptr<BackendText> createText();

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Creates a new texture object
        /// @return Texture that is specific to the backend
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD std::shared_ptr<BackendTexture> createTexture();

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Sets the scale factor to render text at a higher quality, e.g. to scale for DPI awareness
        ///
        /// @param scale  Multiplier for the font size
        ///
        /// Text may be rendered blurry if the font scale doesn't match the ratio between the window size and gui view.
        /// Default scaling is 1. If the scale is set to 1.5 then a font with text size 20 would be internally rendered at 30px.
        ///
        /// The font scale is also used rasterize SVG images at a different resolution.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void setFontScale(float scale);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the scale factor to render text at a higher quality, e.g. to scale for DPI awareness
        ///
        /// @return Multiplier for the font size
        ///
        /// @see setFontScale
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        float getFontScale() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Changes the look of a certain mouse cursor by using a bitmap
        ///
        /// @param type    Cursor that should make use of the bitmap
        /// @param pixels  Pointer to an array with 4*size.x*size.y elements, representing the pixels in 32-bit RGBA format
        /// @param size    Size of the cursor
        /// @param hotspot Pixel coordinate within the cursor image which will be located exactly at the mouse pointer position
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void setMouseCursorStyle(Cursor::Type type, const std::uint8_t* pixels, Vector2u size, Vector2u hotspot) = 0;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Changes the look of a certain mouse cursor back to the system theme
        ///
        /// @param type  Cursor that should no longer use a custom bitmap
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void resetMouseCursorStyle(Cursor::Type type) = 0;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Changes the mouse cursor when the mouse is on top of the window to which the gui is attached
        ///
        /// @param gui   The gui that represents the window for which the mouse cursor should be changed
        /// @param type  Which cursor to use
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void setMouseCursor(BackendGui* gui, Cursor::Type type) = 0;

#ifndef TGUI_REMOVE_DEPRECATED_CODE
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Opens the virtual keyboard on Android and iOS
        /// @param inputRect Part of the screen where the text input is located
        ///
        /// If this function isn't overriden then calling it does nothing.
        ///
        /// @deprecated Replaced by BackendGui::startTextInput in TGUI 1.0
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_DEPRECATED("Use BackendGui::startTextInput instead") virtual void openVirtualKeyboard(const FloatRect& inputRect);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Closes the virtual keyboard on Android and iOS
        ///
        /// If this function isn't overriden then calling it does nothing.
        ///
        /// @deprecated Replaced by BackendGui::stopTextInput in TGUI 1.0
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_DEPRECATED("Use BackendGui::stopTextInput instead") virtual void closeVirtualKeyboard();
#endif

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Checks the state for one of the modifier keys
        ///
        /// @param modifierKey  The modifier key of which the state is being queried
        ///
        /// @return Whether queries modifier key is being pressed
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_DEPRECATED("Use gui.isKeyboardModifierPressed(modifierKey) instead") TGUI_NODISCARD virtual bool isKeyboardModifierPressed(Event::KeyModifier modifierKey);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Changes the contents of the clipboard
        ///
        /// @param contents  New contents of the clipboard
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void setClipboard(const String& contents);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the contents of the clipboard
        ///
        /// @return Clipboard contents
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD virtual String getClipboard() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Uses the AssetManager on Android to read a file and return its contents
        ///
        /// @param filename  Path to the file to read
        /// @param fileSize  Size of the file, to be filled in by this function if loading succeeds (untouched on failure)
        ///
        /// @return File contents if the file was successfully read, or a nullptr on failure or if platform isn't Android.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD virtual std::unique_ptr<std::uint8_t[]> readFileFromAndroidAssets(const String& filename, std::size_t& fileSize) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Checks whether a renderer has been attached to the backend
        /// @return Has setRenderer been called with a valid backend renderer?
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD bool hasRenderer() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the renderer
        ///
        /// @return Renderer attached to the backend
        ///
        /// @warning This function will assert if no renderer has been set.
        /// @see hasRenderer()
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD std::shared_ptr<BackendRenderer> getRenderer() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Sets the renderer that the backend should use
        ///
        /// @param renderer  Renderer to attach to the backend
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void setRenderer(std::shared_ptr<BackendRenderer> renderer);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Checks whether a font factory has been attached to the backend
        /// @return Has setFontBackend been called with a valid font factory?
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD bool hasFontBackend() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the font factory
        ///
        /// @return Font factory attached to the backend
        ///
        /// @warning This function will assert if no font factory has been set.
        /// @see hasFontBackend()
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD std::shared_ptr<BackendFontFactory> getFontBackend() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Sets the font factory that the backend should use
        ///
        /// @param fontBackend  Font factory to attach to the backend
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void setFontBackend(std::shared_ptr<BackendFontFactory> fontBackend);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @internal
        /// @brief Informs the backend about the existence of a font object
        ///
        /// This function gets called internally when creating a BackendFont object. The backend keeps track of font objects
        /// in order to recreate their internals when the font scale is changed.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void registerFont(BackendFont* font);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @internal
        /// @brief Informs the backend about the destruction of a font object
        ///
        /// This function gets called internally when destroying a BackendFont object. The backend keeps track of font objects
        /// in order to recreate their internals when the font scale is changed.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void unregisterFont(BackendFont* font);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @internal
        /// @brief Informs the backend about the existence of a SVG texture
        ///
        /// This function gets called internally when Sprite creates a BackendTexture object for SVG rasterization.
        /// The backend keeps track of these texture objects in order to rasterize again when the font scale is changed.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void registerSvgSprite(Sprite* sprite);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @internal
        /// @brief Informs the backend about the destruction of an SVG texture
        ///
        /// This function gets called internally when Sprite destroys a BackendTexture object for SVG rasterization.
        /// The backend keeps track of these texture objects in order to rasterize again when the font scale is changed.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void unregisterSvgSprite(Sprite* sprite);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    protected:

        bool m_destroyOnLastGuiDetatch = false;
        String m_clipboardContents;
        float m_fontScale = 1;

        std::shared_ptr<BackendRenderer> m_renderer;
        std::shared_ptr<BackendFontFactory> m_fontBackend;

        std::set<BackendGui*> m_guis;
        std::set<BackendFont*> m_registeredFonts;
        std::set<Sprite*> m_registeredSvgSprites;
    };

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif // TGUI_BACKEND_HPP
